//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package impl

import (
	"bytes"
	"context"
	"encoding/json"
	"io"
	"net/http"
	net_url "net/url"
	"strings"
	"time"

	"atomgit.com/openlinksaas-org/search-proxy/core"
	"github.com/antchfx/htmlquery"
)

type OsChinaParser struct{}

type OsChinaRequest struct {
	From    uint32 `json:"from"`
	KeyWord string `json:"keyword"`
	Size    uint32 `json:"size"`
	Type    string `json:"type"`
}

type OsChinaArticle struct {
	Title   string `json:"title"`
	Content string `json:"content"`
	Href    string `json:"href"`
}

type OsChinaResponse struct {
	Articles []OsChinaArticle `json:"articles"`
}

func (parser *OsChinaParser) MatchUrl(url string) bool {
	return strings.HasPrefix(url, "https://www.oschina.net/search")
}

func (parser *OsChinaParser) Parse(url string) ([]*core.SearchEntry, error) {
	urlInfo, err := net_url.Parse(url)
	if err != nil {
		return nil, err
	}
	queryStr := urlInfo.Query().Get("q")
	articleList, err := parser.query(queryStr)
	if err != nil {
		return nil, err
	}

	retList := []*core.SearchEntry{}
	for _, article := range articleList {
		titleNode, err := htmlquery.Parse(bytes.NewBuffer([]byte("<div>" + article.Title + "</div>")))
		if err != nil {
			continue
		}
		summaryNode, err := htmlquery.Parse(bytes.NewBuffer([]byte("<div>" + article.Content + "</div>")))
		if err != nil {
			continue
		}
		retList = append(retList, &core.SearchEntry{
			Title:   htmlquery.InnerText(titleNode),
			Url:     article.Href,
			Summary: htmlquery.InnerText(summaryNode),
		})
	}
	return retList, nil
}

func (parser *OsChinaParser) query(queryStr string) ([]OsChinaArticle, error) {
	reqData, err := json.Marshal(&OsChinaRequest{
		From:    0,
		KeyWord: queryStr,
		Size:    20,
		Type:    "DEFAULT_ALL",
	})
	if err != nil {
		return nil, err
	}
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	req, err := http.NewRequestWithContext(ctx, "POST", "https://www.oschina.net/MjAyMi8xLzE2/v1/search/index", bytes.NewBuffer(reqData))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	respData, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	respObj := &OsChinaResponse{}

	err = json.Unmarshal(respData, respObj)
	if err != nil {
		return nil, err
	}
	return respObj.Articles, nil
}
